package cn.webank.framework.seq.integration.dao.impl;

import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

import cn.webank.framework.data.jedis.pool.JedisPartition;
import cn.webank.framework.data.jedis.pool.MultiJedisShardedPool;
import cn.webank.framework.data.jedis.pool.WeBankShardedJedis;
import cn.webank.framework.seq.integration.dao.SeqMemoryDAO;
import cn.webank.framework.seq.model.SequenceRange;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

@Repository("cn.webank.framework.seq.integration.dao.SeqMemoryDAO")
public class SeqMemoryRedisDAO implements SeqMemoryDAO {
	// private static final int ONE_DAY = 24 * 3600 + 10;

	@Autowired
	@Qualifier("multiJedisShardedPool")
	private MultiJedisShardedPool multiJedisShardedPool;

	@Override
	public boolean isExistsSeq(String namespace, String seqName) {
		WeBankShardedJedis jedis = null;

		JedisPartition jedisShardedPool = null;
		boolean result;
		try {
			jedisShardedPool = multiJedisShardedPool.getJedisPartition(seqName);
			jedis = jedisShardedPool.getReadResource();
			String fk = formatKey(namespace, seqName);
			result = jedis.exists(fk);
		} finally {
			if (jedisShardedPool != null) {
				jedisShardedPool.returnReadResource(jedis);
			}
		}
		return result;

	}

	@Override
	public boolean initSeq(String namespace, String seqName,
			long retryTimeoutMills, int effectSeconds) {
		long lastTime = System.currentTimeMillis();
		Jedis jedis = null;
		JedisPartition jedisShardedPool = null;
		try {
			while (System.currentTimeMillis() - lastTime < retryTimeoutMills) {
				jedisShardedPool = multiJedisShardedPool
						.getJedisPartition(seqName);
				jedis = jedisShardedPool.getReadWriteResource();
				String fk = formatKey(namespace, seqName);
				jedis.watch(fk);

				if (jedis.exists(fk)) {
					jedis.unwatch();
					jedisShardedPool.returnReadWriteResource(jedis);
					jedis = null;
					return true;
				}

				Transaction tx = jedis.multi();
				// 24小时的生命周期
				tx.setex(fk, effectSeconds, "0");
				List<Object> results = tx.exec();
				if (results != null) {
					jedisShardedPool.returnReadWriteResource(jedis);
					jedis = null;
					return true;
				}
			}
		} finally {
			if (jedisShardedPool != null) {
				jedisShardedPool.returnReadWriteResource(jedis);
			}
		}

		return false;

	}

	@Override
	public SequenceRange getSeq(String namespace, String seqName,
			Date currentTime, int step) {
		Jedis jedis = null;
		JedisPartition jedisShardedPool = null;
		SequenceRange sequenceRange = null;
		try {
			jedisShardedPool = multiJedisShardedPool.getJedisPartition(seqName);
			jedis = jedisShardedPool.getReadWriteResource();
			String fk = formatKey(namespace, seqName);
			long maxSeq = jedis.incrBy(fk, step);
			sequenceRange = new SequenceRange(maxSeq - step , maxSeq,
					currentTime);
		} finally {
			if (jedisShardedPool != null) {
				jedisShardedPool.returnReadWriteResource(jedis);
			}
		}

		return sequenceRange;
	}

	private String formatKey(String namespace, String mapName) {
		return namespace + ":" + mapName;
	}

	// public void setSeq(String namespace, String seqName, String value) {
	// Jedis jedis = null;
	// JedisPartition jedisShardedPool = null;
	// try {
	// jedisShardedPool = multiJedisShardedPool.getJedisPartition(seqName);
	// jedis = jedisShardedPool.getReadWriteResource();
	// String fk = formatKey(namespace, seqName);
	// Transaction tx = jedis.multi();
	// tx.set(fk, value);
	// // 24小时的生命周期
	// // tx.setex(fk, ONE_DAY, value);
	// tx.exec();
	// } finally {
	// if (jedisShardedPool != null) {
	// jedisShardedPool.returnReadWriteResource(jedis);
	// }
	// }
	//
	// }

}
